<?php

namespace app\admin\model\facrm;

use think\Model;
use traits\model\SoftDelete;

/**
 * 合同模型
 * Class Contract
 * @package app\admin\model\facrm
 */
class Contract extends Model
{
    use SoftDelete;

    // 表名
    protected $name = 'facrm_contract';
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';
    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    protected $deleteTime = 'delete_time';

    protected static function init()
    {
        $forfun = function (&$row) {
            foreach ($row->data as $k => $v) {

                //数组的字段处理成字符串,主要处理是自定义字段多选的值
                if (!empty($v) && is_array($v)) $row->data[$k] = implode(',', $v);
            }
        };
        self::afterUpdate(
            function ($row) {
                $changed = $row->getChangedData();
                if ($changed && isset($changed['follow_time'])) return;//跟进操作不加日志
                $msg = Operatelog::getTitle() ? "" : "更变合同";
                if ($msg && isset($changed['check_status']) && $changed['check_status']) {
                    //标题存在说明在之前已经赋值过，不再处理
                    $check_status = ['-1' => "未提交", '0' => "待审核", 1 => '审核合同', 2 => '审核通过', 3 => '审核未通过'];
                    $msg = $check_status[$changed['check_status']];
                }

                Operatelog::record(0, $row->id, 0, $msg, json_encode($changed));
            }
        );
        self::afterInsert(function ($row) use ($forfun) {
            //添加操作日志
            Operatelog::record(0, $row->id, 0, Operatelog::getTitle() ? "" : "新增合同", json_encode($row));
        });


        /**
         * 插入前
         */
        self::beforeInsert(function ($row) use ($forfun) {
            $forfun($row);
        });
        /**
         * 更新前
         */
        self::beforeUpdate(function ($row) use ($forfun) {
            $forfun($row);
        });
    }

    /**
     * 创建者
     */
    public function createUser()
    {
        return $this->hasOne('\app\admin\model\Admin', 'id', 'create_user_id');
    }

    /**
     * 拥有者
     */
    public function ownerUser()
    {
        return $this->hasOne('\app\admin\model\Admin', 'id', 'owner_user_id');
    }

    /**
     * 签单人
     * @return \think\model\relation\HasOne
     */
    public function orderAdmin()
    {
        return $this->hasOne('\app\admin\model\Admin', 'id', 'order_admin_id');
    }

    /**
     * 客户对象
     * @return \think\model\relation\BelongsTo
     */
    public function customer()
    {
        return $this->belongsTo('\app\admin\model\facrm\Customer', 'customer_id', 'id');
    }

    /**
     * 联系人
     * @return \think\model\relation\BelongsTo
     */
    public function contacts()
    {
        return $this->belongsTo('\app\admin\model\facrm\customer\Contacts', 'contacts_id');
    }

    /**
     * 商机对象
     * @return \think\model\relation\BelongsTo
     */
    public function business()
    {
        return $this->belongsTo('\app\admin\model\facrm\Business', 'business_id', 'id');
    }

    /**
     * 关联商品
     * @return \think\model\relation\HasMany
     */
    public function product()
    {
        return $this->hasMany('\app\admin\model\facrm\contract\Product', 'contract_id', 'id');
    }

    /**
     * 收款
     * @return \think\model\relation\HasMany
     */
    public function receivables()
    {
        return $this->hasMany('\app\admin\model\facrm\contract\Receivables', 'contract_id', 'id');
    }

    /**
     * 审批日志
     * @return \think\model\relation\HasMany
     */
    public function flowLog()
    {
        return $this->hasMany('\app\admin\model\facrm\flow\Log', 'types_id', 'id')->where('types', 'contract');
    }

    /**
     * 合同、回款统计
     * @param $startDate 开始时间
     * @param $endDate 结束时间
     * @param $owner_user_ids
     * @return array|bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function getAchievementEchart($startDate, $endDate, $owner_user_ids)
    {

        $contractModel = new \app\admin\model\facrm\Contract();
        $receivablesModel = new \app\admin\model\facrm\contract\Receivables();
        // 生成查询的开始和结束时间，默认取30日
        !is_numeric($startDate) && $starttime = strtotime($startDate);
        !is_numeric($endDate) && $endtime = strtotime($endDate);
        $isnotrangeDate = empty($starttime) && empty($endtime);
        $nearly = '30';
        if ($isnotrangeDate) {
            $endtime = time();
            $nearly -= 1;
            $starttime = strtotime("-{$nearly} day");  // 最近30天日期
        } elseif ($starttime > $endtime) {
            $this->error = '起始时间要小于终止时间';
            return false;
        }
        $totalseconds = $endtime - $starttime;;
        if ($totalseconds > 86400 * 30 * 2) {
            $format = '%Y-%m';
        } else {
            if ($totalseconds > 86400) {
                $format = '%Y-%m-%d';
            } else {
                $format = '%H:00';
            }
        }
        //合同数量和合同金额
        if ($owner_user_ids && is_numeric($owner_user_ids)) {
            $contractModel->where('order_admin_id', $owner_user_ids);
            $receivablesModel->where('order_admin_id', $owner_user_ids);
        } elseif ($owner_user_ids && is_array($owner_user_ids)) {
            $contractModel->where('order_admin_id', 'in', $owner_user_ids);
            $receivablesModel->where('order_admin_id', 'in', $owner_user_ids);
        }

        //合同金额
        $lists = $contractModel->where('order_time', 'between time', [$starttime, $endtime])
            ->field('COUNT(*) AS nums, sum(money) as money, DATE_FORMAT(FROM_UNIXTIME(order_time), "' . $format . '") AS add_date')
            ->where('check_status', 2)->group('add_date')
            ->select();
        //回款金额
        $listsd = $receivablesModel->where('return_time', 'between time', [$starttime, $endtime])
            ->field('COUNT(*) AS nums, sum(money) as money, DATE_FORMAT(FROM_UNIXTIME(return_time), "' . $format . '") AS add_date')
            ->where('check_status', 2)->group('add_date')
            ->select();


        if ($totalseconds > 84600 * 30 * 2) {
            $starttime = strtotime('last month', $starttime);
            while (($starttime = strtotime('next month', $starttime)) <= $endtime) {
                $column[] = date('Y-m', $starttime);
            }
        } else {
            if ($totalseconds > 86400) {
                for ($time = $starttime; $time <= $endtime;) {
                    $column[] = date("Y-m-d", $time);
                    $time += 86400;
                }
            } else {
                for ($time = $starttime; $time <= $endtime;) {
                    $column[] = date("H:00", $time);
                    $time += 3600;
                }
            }
        }


        $r_count = $c_count = $c_money = $r_money = array_fill_keys($column, 0);

        foreach ($lists as $k => $v) {
            $c_count[$v['add_date']] = $v['nums'];//合同数量
            $c_money[$v['add_date']] = $v['money'];//合同金额
        }

        foreach ($listsd as $k => $v) {
            $r_money[$v['add_date']] = $v['money'];//回款金额
            $r_count[$v['add_date']] = $v['nums'];//回款数量
        }

        $result = [
            'date' => array_keys($c_count),
            'c_money' => array_values($c_money),
            'c_count' => array_values($c_count),
            'r_money' => array_values($r_money),
            'r_count' => array_values($r_count),
        ];

        $data = [
            'date' => $result['date'],
            'data' => [
                "合同数量" => $result['c_count'],
                "合同金额" => $result['c_money'],
                "回款金额" => $result['r_money'],
                "回款数量" => $result['r_count'],
            ],
        ];
        return $data;
    }

    /**
     * 根据规则自动生成编码
     * @param $prefix
     * @return int|mixed|string
     */
    public static function autoNo($prefix)
    {
        $replace_data = ['Y' => date('Y'), 'm' => date('m'), 'd' => date('d'), 'h' => date("H"), 'i' => date("i"), 's' => date("s"), 'rand' => rand(100000, 999999)];
        return $prefix ? __($prefix, $replace_data) : '';
    }


    /**
     * 修改
     * @param $row 当前修改的实体
     * @param $params 参数
     * @param $product_data 商品集
     */
    public function edit($row, $params, $product_data)
    {
        //是否采用模型验证
        $name = str_replace("\\model\\", "\\validate\\", get_class($this));
        $row->validateFailException(true)->validate($name . '.edit');

        $contract_id = $row->id;
        $result = $row->allowField(true)->save($params);
        if ($result) {
            //更新产品,先全部删除再添加
            $productModel = new \app\admin\model\facrm\product\Product();
            foreach ($row->product as $p) {
                $p->info()->setInc('inventory', $p['nums']);//恢复库存
                $p->delete();
            }

            $i = 1;
            foreach ($product_data as $key => &$r) {
                if (!$r['nums']) \exception("数量不对 {$i}行");
                $r['contract_id'] = $contract_id;
                $pinfo = $productModel->where('id', $r['product_id'])->where('status', 1)->find();
                if (!$pinfo) {
                    \exception("产品不存在， {$i}行");
                }
                //判断产品库存
                if ($pinfo['inventory'] < $r['nums']) {
                    \exception($pinfo['name'] . "库存不足， {$i}行");
                }
                $r['price'] = $pinfo['price'];
                $r['discount'] = $params['discount_rate'] ? $params['discount_rate'] : 0; //优惠
                $r['sales_price'] = bcsub($pinfo['price'], $r['discount'] * $pinfo['price'] / 100, 2);//销售价格
                $r['subtotal'] = bcmul($r['sales_price'], $r['nums'], 2);//销售价格小计
                $r['unit'] = $pinfo['unit'];//单位
                $i++;
                //减少库存
                $pinfo->setDec('inventory', $r['nums']);
            }
            $row->product()->saveAll($product_data);
        }
        return $result;
    }

    /**
     * 添加
     * @param $params 参数
     * @param $product_data 商品集
     */
    public function add($params, $product_data)
    {
        //是否采用模型验证
        $name = str_replace("\\model\\", "\\validate\\", get_class($this));
        $this->validateFailException(true)->validate($name . '.add');

        $result = $this->allowField(true)->save($params);
        //添加商机产品
        $contract_id = $this->id;
        $productModel = new \app\admin\model\facrm\product\Product();
        $i = 1;
        foreach ($product_data as $key => &$row) {
            if (!$row['nums']) \exception("数量不对 {$i}行");
            $row['contract_id'] = $contract_id;
            $pinfo = $productModel->where('id', $row['product_id'])->where('status', 1)->find();
            if (!$pinfo) {
                \exception("产品不存在， {$i}行");
            }
            //判断产品库存
            if (($pinfo['inventory']) < $row['nums']) {
                \exception($pinfo['name'] . "库存不足， {$i}行");
            }
            $row['price'] = $pinfo['price'];
            $row['discount'] = $params['discount_rate'] ? $params['discount_rate'] : 0; //优惠
            $row['sales_price'] = bcsub($pinfo['price'], $row['discount'] * $pinfo['price'] / 100, 2);//销售价格
            $row['subtotal'] = bcmul($row['sales_price'], $row['nums'], 2);//销售价格小计
            $row['unit'] = $pinfo['unit'];//单位
            $i++;
            //减少库存
            $pinfo->setDec('inventory', $row['nums']);
        }

        $this->product()->saveAll($product_data);
        return $result;

    }

}